/*
 * Teknei 2014 - All rights reserved
 */
package com.teknei.acabus.core.persistence.dao.impl;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.teknei.acabus.PersistenceException;
import com.teknei.acabus.core.persistence.dao.GenericDAO;

/**
 * Session Bean implementation class GenericDAOBean
 * @author Jorge Amaro
 * @version 1.0
 * @since 1.0
 */
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class GenericDAOBean<T> implements GenericDAO<T> {

	@PersistenceContext
	EntityManager em;

	private Class<T> entityClass;

	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	public GenericDAOBean() {
		super();
		ParameterizedType genericSuperclass = (ParameterizedType) getClass()
				.getGenericSuperclass();
		this.entityClass = (Class<T>) genericSuperclass
				.getActualTypeArguments()[0];
	}

	/* (non-Javadoc)
	 * @see com.teknei.acabus.core.persistence.dao.GenericDAO#create(java.lang.Object)
	 */
	@Override
	public T create(T t) throws PersistenceException {
		try {
			this.em.persist(t);
			this.em.flush();
			this.em.refresh(t);
			return t;
		} catch (Exception e) {
			throw new PersistenceException("Error in create:" + e.getMessage(),
					e);
		}

	}

	/* (non-Javadoc)
	 * @see com.teknei.acabus.core.persistence.dao.GenericDAO#find(java.lang.Class, java.lang.Object)
	 */
	@Override
	public T find(Class<T> type, Object id) throws PersistenceException {
		try {
			return (T) this.em.find(type, id);
		} catch (Exception e) {
			throw new PersistenceException("Error in find:" + e.getMessage(), e);
		}
	}

	/* (non-Javadoc)
	 * @see com.teknei.acabus.core.persistence.dao.GenericDAO#delete(java.lang.Class, java.lang.Object)
	 */
	@Override
	public void delete(Class<T> type, Object id) throws PersistenceException {
		try {
			Object ref = this.em.getReference(type, id);
			this.em.remove(ref);
		} catch (Exception e) {
			throw new PersistenceException("Error in delete:" + e.getMessage(),
					e);
		}

	}
	
	/* (non-Javadoc)
	 * @see com.teknei.acabus.core.persistence.dao.GenericDAO#delete(java.lang.Object)
	 */
	@Override
	public void delete(T entity) throws PersistenceException{
		try{
			entity = em.merge(entity);
			this.em.remove(entity);
			em.flush();
		}catch (Exception e) {
			throw new PersistenceException("Error in delete:" + e.getMessage(),
					e);
		}
	}

	/* (non-Javadoc)
	 * @see com.teknei.acabus.core.persistence.dao.GenericDAO#update(java.lang.Object)
	 */
	@Override
	public T update(T t) throws PersistenceException {
		try {
			return (T) this.em.merge(t);
		} catch (Exception e) {
			throw new PersistenceException("Error in update:" + e.getMessage(),
					e);
		}
	}

	/* (non-Javadoc)
	 * @see com.teknei.acabus.core.persistence.dao.GenericDAO#findWithNamedQuery(java.lang.String)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> findWithNamedQuery(String namedQueryName)
			throws PersistenceException {
		try {
			return this.em.createNamedQuery(namedQueryName).getResultList();
		} catch (Exception e) {
			throw new PersistenceException("Error in findWithNamedQuery:"
					+ e.getMessage(), e);
		}
	}

	/* (non-Javadoc)
	 * @see com.teknei.acabus.core.persistence.dao.GenericDAO#findByNativeQuery(java.lang.String, java.lang.Class)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> findByNativeQuery(String sql, Class<T> type)
			throws PersistenceException {
		try {
			return this.em.createNativeQuery(sql, type).getResultList();
		} catch (Exception e) {
			throw new PersistenceException("Error in findByNativeQuery:"
					+ e.getMessage(), e);
		}
	}

	/* (non-Javadoc)
	 * @see com.teknei.acabus.core.persistence.dao.GenericDAO#findAll()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<T> findAll() throws PersistenceException {
		try {
			Query q = getEm().createQuery(
					"SELECT e FROM " + entityClass.getName() + " e");
			List<T> list = (List<T>) q.getResultList();
			return list;
		} catch (Exception e) {
			throw new PersistenceException(
					"Error in findAll:" + e.getMessage(), e);
		}
	}

	/**
	 * @return the em
	 */
	public EntityManager getEm() {
		return em;
	}

	/**
	 * @param em
	 *            the em to set
	 */
	public void setEm(EntityManager em) {
		this.em = em;
	}

	/**
	 * @return the entityClass
	 */
	public Class<T> getEntityClass() {
		return entityClass;
	}

	/**
	 * @param entityClass
	 *            the entityClass to set
	 */
	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

}
